#ifndef VISITOR_HPP
#define VISITOR_HPP

class Node;
  class ListNode;
  class PrintNode;
  class ReturnNode;
  class BinaryOp;
    class CmpNode;
  class LogicNotNode;
  class ConstInt;
  class ConstString;
  class ConstArray;
  class IfNode;
  class WhileNode;
  class AssignNode;
  class VarNode;
  class VarDefNode;
  class ParamDefNode;
  class FuncDefNode;
  class LambdaDef;
  class CallNode;
  class SubscrNode;
  class BuiltinConst;

  class ArrowTypeNode;
  class ArrayTypeNode;

  class TypeVarNode;
  class TypeFuncDefNode;
  class TypeVarDefNode;
  class TypeCallNode;
  class TypeConstInt;

class Visitor {
public:
    void visit(Node* n);

    virtual void visit(PrintNode* n) = 0;
    virtual void visit(ReturnNode* n) = 0;
    virtual void visit(BinaryOp* n) = 0;
    virtual void visit(LogicNotNode* n) = 0;
    virtual void visit(ListNode* n) = 0;
    virtual void visit(ConstInt* n) = 0;
    virtual void visit(ConstString* n) = 0;
    virtual void visit(ConstArray* n) = 0;
    virtual void visit(IfNode* n) = 0;
    virtual void visit(WhileNode* n) = 0;
    virtual void visit(CmpNode* n) = 0;
    virtual void visit(AssignNode* n) = 0;
    virtual void visit(VarNode* n) = 0;
    virtual void visit(VarDefNode* n) = 0;
    virtual void visit(ParamDefNode* n) = 0;
    virtual void visit(FuncDefNode* n) = 0;
    virtual void visit(LambdaDef* n) = 0;
    virtual void visit(CallNode* n) = 0;
    virtual void visit(SubscrNode* n) = 0;
    virtual void visit(BuiltinConst* n) = 0;

    virtual void visit(ArrowTypeNode* n) = 0;
    virtual void visit(ArrayTypeNode* n) = 0;

    virtual void visit(TypeVarNode* n) = 0;
    virtual void visit(TypeFuncDefNode* n) = 0;
    virtual void visit(TypeVarDefNode* n) = 0;
    virtual void visit(TypeCallNode* n) = 0;
    virtual void visit(TypeConstInt* n) = 0;
};

class Dumper : public Visitor {
private:
    int _indent;
    inline void print_indent();
public:
    Dumper() : _indent(0) {}

    void visit(Node* n);

    virtual void visit(PrintNode* n);
    virtual void visit(ReturnNode* n);
    virtual void visit(BinaryOp* n);
    virtual void visit(LogicNotNode* n);
    virtual void visit(ListNode* n);
    virtual void visit(ConstInt* n);
    virtual void visit(ConstString* n);
    virtual void visit(ConstArray* n);
    virtual void visit(IfNode* n);
    virtual void visit(WhileNode* n);
    virtual void visit(CmpNode* n);
    virtual void visit(AssignNode* n);
    virtual void visit(VarNode* n);
    virtual void visit(VarDefNode* n);
    virtual void visit(ParamDefNode* n);
    virtual void visit(FuncDefNode* n);
    virtual void visit(LambdaDef* n);
    virtual void visit(CallNode* n);
    virtual void visit(SubscrNode* n);
    virtual void visit(BuiltinConst* n);

    virtual void visit(ArrowTypeNode* n);
    // builtin, empty
    virtual void visit(ArrayTypeNode* n) {};

    virtual void visit(TypeVarNode* n);
    virtual void visit(TypeFuncDefNode* n);
    virtual void visit(TypeVarDefNode* n);
    virtual void visit(TypeCallNode* n);
    virtual void visit(TypeConstInt* n);
};

#endif
